Terraform Cloudを使って複数環境(本番/STG)にAWSリソースをデプロイしてみる
「STGと本番のAWSアカウントにTerraform Cloudでリソースをデプロイするにはどんな設定をすればいいんだろう?」
実際のシステム運用では、本番とSTGなど複数の環境を作ることが多いと思います。
このブログが、Terraform Cloudで複数環境を設定する際の参考になると嬉しいです。
構成図
本番環境とSTG環境のAWSアカウントがそれぞれ存在して、Terraformのコード上で本番とSTGでstateが分かれているとします。
Terraform Cloud上ではシステム用にProjectを作り、その中に本番環境とSTG環境のWorkspaceを作る構成です。
デプロイフロー
今回は上記のデプロイフローを想定して、Terraform Cloudを設定していきます。
- mainブランチにPull Request
- Terraform Cloud上で本番とSTG環境のPlan実行
- Pull Requestのマージ時に、STG環境にApply実行
- Terraform Cloudのコンソールから手動承認後、本番環境にApply実行
STG環境は自動適用で、本番環境はSTG環境の状態を確認した上で手動承認して、Terraformを適用するという流れです。
やってみた
コードを見てみる
使用するコードは以下リポジトリの、infra/配下になります。
AWSリソース作成のTerraformコードは、EC2を作成するだけの内容です。
provider "aws" { region = "ap-northeast-1" default_tags { tags = { Env = "stg" Terraform = "true" SystemName = "tfc-demo" } } } terraform { required_providers { aws = { source = "hashicorp/aws" version = "~> 4.52.0" } } } module "vpc" { source = "terraform-aws-modules/vpc/aws" name = "stg-vpc" cidr = "10.10.0.0/16" azs = ["ap-northeast-1a", "ap-northeast-1c"] private_subnets = ["10.10.1.0/24", "10.10.2.0/24"] public_subnets = ["10.10.101.0/24", "10.10.102.0/24"] } module "ec2" { source = "../../modules/ec2" subnet_id = module.vpc.private_subnets[0] instance_name = "tfc-demo-stg" }
data aws_ssm_parameter amzn2_ami { name = "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2" } resource "aws_network_interface" "this" { subnet_id = var.subnet_id } resource "aws_instance" "this" { ami = data.aws_ssm_parameter.amzn2_ami.value instance_type = var.instance_type network_interface { network_interface_id = aws_network_interface.this.id device_index = 0 } tags = { Name = var.instance_name } }
Projectの作成
まずは、今回作成するデモシステム用にProjectを作成します。
Project名は以下とします。
- Project名:
multi-env-demo
Projectの分け方も色々考え方があると思いますが、今回はシステムごとに分けるようなイメージで作っていきます。
作成したProject内にSTG環境と本番環境のWorkspaceを作成していきます。
STG Workspaceの作成
Workspaceはstateファイルごとに作成します。
今回はデモ用でリソース数が少ないので、本番とSTGといった単位でstateを分けています。 そのため、Workspaceも本番とSTGで合計2つ作成します。
まずは、STGのWorkspaceを作ります。
先ほど作成したProjectを選択して、Workspaceを作成します。
- Workspace名:
multi-env-demo-stg
デモ用のGithubリポジトリと接続するように設定していきます。
ProjectとWorkspace名を設定して、Create Workspace
を選択します。
STG環境 Workspaceの設定
Workspaceを作成できたところで、必要な設定をしていきます。
multi-env-demo-stg
> Settings
に遷移します。
以下を設定します。
- Apply Method:
Auto Apply
- Terraform Working Directory:
infra/environments/stg
- VCS branch:
main
Apply Method
はterraform apply
の適用に関する設定です。
デフォルトはManula apply
となっており、手動承認が必要な形です。
今回は、STG環境はPull RequestをMergeした際(デフォルトブランチへのPush時)にApplyを実行したいので、Auto Apply
にします。
Terraform Working Directory
は、Terraformを実行するディレクトリです。
ここで設定したディレクトリで、terraform関連のコマンドが実行されます。
今回はディレクトリで環境を分けているため、STG環境のディレクトリであるinfra/environments/stg
を設定しました。
本番環境 Workspaceの作成
STGと同様に本番 Workspaceを作成します。
STGと異なる点は、Workspace名のみです。
- Workspace名:
multi-env-demo-prod
本番環境 Workspaceの設定
STGと同様にWorkspaceの設定を行います。
- Apply Method:
Manual apply
- Terraform Working Directory:
infra/environments/prod
- VCS branch:
main
Apply Method
はManual apply
として、Terraform Cloud上での手動承認を必要な形にします。
Manual apply
にしておくと、Plan後に以下のように承認を求められるようになります。
Terraform CloudでAWSを使用するための準備
Terraform CloudがAWSリソースを管理できるように、Terraform Cloud用の本番環境とSTG環境Workspace用にそれぞれIAMロールを作成します。
IAMロール作成の詳細な手順は以下をご確認ください。
IAMロールには以下のポリシーをアタッチしてください。
Terraform Cloud用のIAMロールポリシー
{ "Statement": [ { "Action": [ "ec2:*", "ssm:*" ], "Effect": "Allow", "Resource": "*" } ], "Version": "2012-10-17" }
信頼関係は以下のように設定します。
Terraform Cloud用のIAMロール 信頼関係
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Federated": "arn:aws:iam::[アカウントID]:oidc-provider/app.terraform.io" }, "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringEquals": { "app.terraform.io:aud": "aws.workload.identity" }, "StringLike": { "app.terraform.io:sub": "organization:[Organization名]:project:multi-env-demo:workspace:multi-env-demo-stg:run_phase:*" } } } ] }
※本番環境用IAMロールは、Workspace名multi-env-demo-stg
の部分はmulti-env-demo-prd
にします。
IAMロールを作成したら、STGと本番のWorkspaceの環境変数に以下を設定します。
TFC_AWS_PROVIDER_AUTH
:true
TFC_AWS_RUN_ROLE_ARN
:IAMロールのARN
動作確認
Pull Request時に各WorkspaceでPlan
Pull Request時に各WorkspaceでPlanが実行されることを確認します。
infra/envirionments/prod
とinfra/environments/stg
のtfファイルを少し変更してPull Requestを出してみます。
以下のように本番とSTGのWorkspaceでPlanが走っていることがGithub上からも確認できます。
Detail
の部分をクリックするとTerraform Cloudに飛んで詳細を確認できます。
Pull Requestマージ時にSTG WorkspaceのApply
次にPull Requestマージ時にSTG WorkspaceのApplyが実行されることを確認します。
マージしました。Terraform Cloudを見てみましょう。
Workspaceのステータスとみると、STG WorkspaceがApplyed
になっておりApplyが実行されいることがわかります。
また、この時点では本番 Workspaceの方はApplyが実行されていません。
マージ後手動で本番WorkspaceのApply
最後にSTGで動作確認が問題なかったことを想定して、本番に変更を適用しましょう。
Terraform Cloudの本番 Workspaceで手動承認を行います。
Confirm & Apply
を選択します。
無事Applyが成功しました。
おわりに
Terraform Cloudを使った複数環境へのAWSリソース デプロイの例でした。
今回は本番もSTGも同一ブランチを使った例を紹介しましたが、本番とSTGでブランチを分けている場合もあると思います。
その際は、STG環境 WorkspaceのVCS Settingの部分でSTG環境用のブランチを指定すれば良いです。
他にも、Runのトリガーでは特定のフォルダ配下の変更時などを設定することができ、柔軟にデプロイフローを作成可能です。
以上、AWS事業本部の佐藤(@chari7311)でした。